package com.fjw.car_send;

import java.util.Arrays;
import java.util.List;

import android.Manifest;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.*;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.util.Log;
import android.util.SizeF;
import android.view.*;
import android.widget.Toast;

public class MainActivity extends Activity {
    private static final int REQUEST_CAMERA_PERMISSION = 2;
    private static MainActivity instance;
    private static final int REQUEST_ENABLE_BT = 0;
    private static final int REQUEST_BLUETOOTH_PERMISSIONS = 1;
    private static final String SERVICE_UUID = "4fafc201-1fb5-459e-8fcc-c5c9c331914b";
    private static final String CHARACTERISTIC_UUID = "beb5483e-36e1-4688-b7f5-ea07361b26a8";
    static final String LOG_TAG = "car_send_activity";
    BluetoothAdapter mBluetoothAdapter;
    BluetoothDevice mBluetoothDevice;
    BluetoothGatt mBluetoothGatt;

    BluetoothGattCharacteristic mBluetoothGattCharacteristic;
    private int mFBLevel = 0;
    private int mLRLevel = 0;
    private int mBeep = 0;
    private int mLed = 0;
    private int mLastFBLevel = 0;
    private int mLastLRLevel = 0;
    private int mLastBeep = 0;
    private int mLastLed = 0;
    Boolean hasWait = false;
    boolean mRunning = false;
    Thread mReadRssiThread;
    Thread mSendDataThread;
    int mSignlLevel = 0;
    int[] mRssiHistory = new int[10];
    int mRssiIndex = 0;
    private CameraManager mCameraManager;
    private String mCameraId;
    CameraCharacteristics mCharacteristics;

    SizeF mPreviewSize = new SizeF(100, 100);
    CameraDevice mCameraDevice;

    public MainActivity() {
        super();
        MainActivity.instance = this;
    }

    public static MainActivity getInstance() {
        return MainActivity.instance;
    }

    Runnable mReadRssiRunnable = new Runnable() {
        @Override
        public void run() {
            while (mRunning) {
                if (checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                    continue;
                }
                if (mBluetoothGatt != null) {
                    mBluetoothGatt.readRemoteRssi();
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };
    Runnable mSendDataRunnable = new Runnable() {
        @Override
        public void run() {
            while (mRunning) {
                doSendData();
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };

    BluetoothGattCallback mBluetoothGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                // 连接成功，开始发现服务
                if (checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                    requestBLEPermissions();
                    return;
                }
                mBluetoothGatt.discoverServices();
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                stopBLE();
                startBLE();
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                // 服务发现成功
                if (checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                    requestBLEPermissions();
                    return;
                }
                List<BluetoothGattService> services = gatt.getServices();
                Log.d(LOG_TAG, "onServicesDiscovered: " + services.size());
                for (BluetoothGattService service : services) {
                    if (service.getUuid().toString().equals(SERVICE_UUID)) {
                        Log.d(LOG_TAG, "onServicesDiscovered: " + service.getUuid().toString());
                        List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics();
                        for (BluetoothGattCharacteristic characteristic : characteristics) {
                            if (characteristic.getUuid().toString().equals(CHARACTERISTIC_UUID)) {
                                // 写入数据
                                mBluetoothGattCharacteristic = characteristic;
                                mBluetoothGattCharacteristic.setValue("0#0#0");
                                mBluetoothGatt.writeCharacteristic(mBluetoothGattCharacteristic);
                            }
                        }
                    }
                }
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,
                int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                // 读取特征值成功
                byte[] data = characteristic.getValue();
                // 处理特征值数据
            }
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,
                int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                // 写入特征值成功
            }
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            // 特征值改变
            byte[] data = characteristic.getValue();
            // 处理特征值数据
        }

        @Override
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                mRssiHistory[mRssiIndex] = rssi;
                if (mRssiIndex == mRssiHistory.length - 1) {
                    mRssiIndex = 0;
                } else {
                    mRssiIndex++;
                }
                int avgRssi = 0;
                for (int j : mRssiHistory) {
                    avgRssi += j;
                }
                avgRssi /= mRssiHistory.length;

                Log.d(LOG_TAG, "onReadRemoteRssi: " + rssi);
                if (avgRssi > -60) {
                    mSignlLevel = 3;
                } else if (avgRssi > -70) {
                    mSignlLevel = 2;
                } else if (avgRssi > -87) {
                    mSignlLevel = 1;
                } else {
                    mSignlLevel = 0;
                }
            } else {
                Log.d(LOG_TAG, "onReadRemoteRssi status: " + status);
            }
        }
    };

    public void setActivityIndex(int index) {
        SharedPreferences prefs = getSharedPreferences("STATE", MODE_PRIVATE);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putInt("index", index);
        editor.apply();
        this.finish();
    }

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mRunning = true;
        // 写入数据
        SharedPreferences prefs = getSharedPreferences("STATE", MODE_PRIVATE);
        // 读取数据
        int activityIndex = prefs.getInt("index", 0);
        if (activityIndex == 0) {
            setContentView(R.layout.activity_main);
            mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
            if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[] { Manifest.permission.CAMERA }, REQUEST_CAMERA_PERMISSION);
            }
        } else {
            setContentView(R.layout.activity_main_1);
        }

        Window window = getWindow();
        window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        window.setStatusBarColor(Color.TRANSPARENT);
        View decorView = getWindow().getDecorView();
        decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);

        Log.d(LOG_TAG, "onCreate");
        BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();
        startBLE();
        mReadRssiThread = new Thread(mReadRssiRunnable);
        mReadRssiThread.start();
        mSendDataThread = new Thread(mSendDataRunnable);
        mSendDataThread.start();
    }

    @Override
    protected void onResume() {
        super.onResume();
        SharedPreferences prefs = getSharedPreferences("STATE", MODE_PRIVATE);
        // 读取数据
        int activityIndex = prefs.getInt("index", 0);
        if (activityIndex == 0) {
            // startCamera();
        }

    }

    private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice cameraDevice) {
            createCameraPreviewSession(cameraDevice);
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice cameraDevice) {
            cameraDevice.close();
        }

        @Override
        public void onError(@NonNull CameraDevice cameraDevice, int i) {
            cameraDevice.close();
        }
    };

    private void startCamera() {
        try {
            mCameraId = mCameraManager.getCameraIdList()[0]; // 默认选择第一个摄像头
            mCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId);
            if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[] { Manifest.permission.CAMERA }, REQUEST_CAMERA_PERMISSION);
                return;
            }
            mCameraManager.openCamera(mCameraId, mStateCallback, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private Runnable createCameraPreviewSessionRunnable = new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            runOnUiThread(createCameraPreviewSessionRunnableUI);

        }
    };
    private Runnable createCameraPreviewSessionRunnableUI = new Runnable() {
        @Override
        public void run() {
            createCameraPreviewSession(mCameraDevice);
        }
    };

    private void createCameraPreviewSession(CameraDevice cameraDevice) {
        TextureView textureview = findViewById(R.id.textureView);
        configureTransform(textureview);
        SurfaceTexture texture = ((TextureView) findViewById(R.id.textureView)).getSurfaceTexture();
        if (texture == null) {
            mCameraDevice = cameraDevice;
            Thread t = new Thread(createCameraPreviewSessionRunnable);
            t.start();
            return;
        }

        texture.setDefaultBufferSize((int) mPreviewSize.getWidth(), (int) mPreviewSize.getHeight());
        Surface surface = new Surface(texture);

        try {
            cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    try {
                        setupPreview(session, cameraDevice, surface);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                    Log.e(LOG_TAG, "Camera configuration failed");
                }
            }, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private void setupPreview(CameraCaptureSession session, CameraDevice cameraDevice, Surface surface)
            throws CameraAccessException {
        int sensorOrientation = mCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
        CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        builder.addTarget(surface);
        session.setRepeatingRequest(builder.build(), null, null);
    }

    private void configureTransform(TextureView view) {
        int viewWidth = view.getWidth();
        int viewHeight = view.getHeight();
        int rotation = getWindowManager().getDefaultDisplay().getRotation();
        Matrix matrix = new Matrix();
        RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
        RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth()); // 注意宽度和高度可能需要交换
        float centerX = viewRect.centerX();
        float centerY = viewRect.centerY();
        if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
            bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
            matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
            float scale = Math.max(
                    (float) viewHeight / mPreviewSize.getHeight(),
                    (float) viewWidth / mPreviewSize.getWidth());
            matrix.postScale(scale, scale, centerX, centerY);
            matrix.postRotate(90 * (rotation - 2), centerX, centerY);
        } else {
            // 其他旋转情况的处理
        }
        view.setTransform(matrix);
    }

    @Override
    protected void onDestroy() {
        mRunning = false;
        while (true) {
            try {
                mReadRssiThread.join();
                break;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        while (true) {
            try {
                mSendDataThread.join();
                break;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        stopBLE();
        super.onDestroy();
    }

    private void requestBLEPermissions() {
        requestPermissions(
                new String[] { Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN,
                        Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN,
                        Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION },
                REQUEST_BLUETOOTH_PERMISSIONS);
    }

    private void startScanning() {
        Log.d(LOG_TAG, "startScanning");
        // 扫描蓝牙设备
        if (checkSelfPermission(Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
            requestBLEPermissions();
            return;
        }
        // 执行扫描操作
        ScanCallback callback = new ScanCallback() {
            @Override
            public void onScanResult(int callbackType, ScanResult result) {
                // 处理扫描结果
                // Log.d(LOG_TAG, "onScanResult: ");
                if (checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                    requestBLEPermissions();
                    return;
                }
                String name = result.getDevice().getName();
                // Log.d(LOG_TAG, "onScanResult: " + name);
                if (name != null && name.contains("ESP32-Car")) {
                    mBluetoothDevice = result.getDevice();
                    mBluetoothAdapter.getBluetoothLeScanner().stopScan(this);
                    connectToDevice();
                }
            }

            @Override
            public void onScanFailed(int errorCode) {
                Log.e(LOG_TAG, "onScanFailed: " + errorCode);
                startScanning();
            }

            @Override
            public void onBatchScanResults(List<ScanResult> results) {
                Log.d(LOG_TAG, "onBatchScanResults: ");
                if (checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                    requestBLEPermissions();
                    return;
                }
                for (ScanResult result : results) {
                    String name = result.getDevice().getName();
                    Log.d(LOG_TAG, "onBatchScanResults: " + name);
                    if (name != null && name.contains("ESP32-Car")) {
                        mBluetoothDevice = result.getDevice();
                        mBluetoothAdapter.getBluetoothLeScanner().stopScan(this);
                        connectToDevice();
                        break;
                    }
                }
            }
        };
        mBluetoothAdapter.getBluetoothLeScanner().startScan(callback);

    }

    private void connectToDevice() {

        if (checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
            requestBLEPermissions();
            return;
        }
        if (mBluetoothDevice == null) {
            Log.e(LOG_TAG, "connectToDevice: mBluetoothDevice is null");
            startBLE();
            return;
        }
        mBluetoothGatt = mBluetoothDevice.connectGatt(this, false, mBluetoothGattCallback);

    }

    private void startBLE() {
        if (!mBluetoothAdapter.isEnabled()) {
            enableBluetooth();
        } else {
            startScanning();
        }
    }

    private void stopBLE() {
        if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
            if (checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
            if (mBluetoothGatt != null) {
                mBluetoothGatt.disconnect();
                mBluetoothGatt.close();
                mBluetoothGatt = null;
            }
            mBluetoothGattCharacteristic = null;
        }
    }

    private void enableBluetooth() {
        Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        if (checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
            requestBLEPermissions();
            return;
        }
        startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        if (requestCode == REQUEST_BLUETOOTH_PERMISSIONS) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                startBLE();
            }
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_ENABLE_BT) {
            if (resultCode == Activity.RESULT_OK) {
                startScanning();
            } else {
                Toast.makeText(this, "蓝牙未开启", Toast.LENGTH_SHORT).show();
            }
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

    public void sendData(int upDownLevel, int leftRightLevel, int beep, int led) {
        synchronized (this) {
            mFBLevel = upDownLevel;
            mLRLevel = leftRightLevel;
            mBeep = beep;
            mLed = led;
            Log.d(LOG_TAG, "sendData set: " + mFBLevel + " " + mLRLevel + " " + mBeep + " " + mLed);
        }

    }

    private void doSendData() {
        int x, y, beep, led;
        synchronized (this) {
            if (mFBLevel == mLastFBLevel
                    && mLRLevel == mLastLRLevel
                    && mBeep == mLastBeep
                    && mLed == mLastLed) {
                return;
            }
            mLastFBLevel = mFBLevel;
            mLastLRLevel = mLRLevel;
            mLastBeep = mBeep;
            mLastLed = mLed;
            y = (int) (((float) mFBLevel) / 3 * 100);
            x = (int) (((float) mLRLevel) / 3 * 100);
            beep = mBeep;
            led = mLed;
        }
        Log.d(LOG_TAG, "doSendData before: " + mFBLevel + " " + mLRLevel + " " + mBeep + " " + mLed);
        if (mBluetoothGattCharacteristic != null) {
            if (checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                requestBLEPermissions();
                return;
            }
            String data = String.format("%d#%d#%d#%d", y, x, beep, led);
            Log.d(LOG_TAG, "doSendData: " + data);
            mBluetoothGattCharacteristic.setValue(data);
            mBluetoothGatt.writeCharacteristic(mBluetoothGattCharacteristic);
        }
    }

    public BluetoothGatt getmBluetoothGatt() {
        return mBluetoothGatt;
    }

    public int getmSignlLevel() {
        return mSignlLevel;
    }

}
